<?php
include_once 'common_functions.php';

//========================================================
// Contains all our SQL statements
//========================================================
class QueryBuilder {
	// tables
	const answers_table = 'Answers';
	const candidates_table = 'Candidates';
	const elections_table = 'Elections';
	const questions_table = 'Questions';
	const votes_table = 'Votes';

	//========================================================
	// Returns: 2 dimensional array of question strings[0][y]
	// and questions IDs[1][y]
	// 
	// Called:
	// Questions.php - 1
	// Process.php - 1
	//========================================================
	static function getAllQuestionsForCurrentElection() {
		// make statement
		$query = "SELECT Q.question_string, Q.ID FROM " . QueryBuilder::questions_table . " AS Q WHERE Q.election_id = " . Config::active_election . " ORDER BY Q.ID ASC;";

		// execute it
		$result = queryDB($query);

		// turn the result set into a 2 dimensional array of questions and question ID's
		$questions[0][0] = "";
		$i = 0;
		while( $row = mysql_fetch_array($result) )
		{
			$questions[0][$i] = $row[0];
			$questions[1][$i] = $row[1];
			$i++;
		}

		return $questions;
	}
	
	//========================================================
	// Returns: the total amount of questions this election
	// 
	// Called: 
	// step_3_view.php - q*c (where q = number of questions and c = number of candidates)
	//========================================================
	static function getCountOfQuestionsForCurrentElection() {
		// quick fix - TODO remove later
		return 40;
		
		// make statement
		$query = "SELECT COUNT(Q.ID) FROM " . QueryBuilder::questions_table . " AS Q WHERE Q.election_id = " . Config::active_election . ";";

		// execute it
		$result = queryDB($query);

		$row = mysql_fetch_array($result);
		

		return $row[0];
	}
	
	//========================================================
	// Returns: 2 dimensional array
	// return[questionID][0] contains the answer value
	// return[questionID][1] contains the important check
	// return[questionID][2] will contain the score
	//
	// Called:
	// Questions.php - 1
	// Process.php - n (where n = number of candidates) !!
	//========================================================
	static function getAllAnswersForCandidateID($candidate) {
		$questions;
		$candidate = sanitize($candidate);
		
		$query = "SELECT A.question_id, A.answer, A.important, A.explanation FROM " . QueryBuilder::answers_table . " AS A WHERE A.candidate_id = " . $candidate . ";";

		// execute it
		$result = queryDB($query);
		//echo 'for: ' . $candidate . '<br />';
		while( $row = mysql_fetch_array($result) )
		{
			//echo $row[0] . ' ' . $row[1] . ' ' . $row[2] . '<br />';
			$questions[$row[0]][0] = $row[1]; // answer
			$questions[$row[0]][1] = $row[2]; // important
			$questions[$row[0]][2] = 0; 
			$questions[$row[0]][3] = $row[3];
		}

		if(!isSet($questions))
			$questions = array();
			
		return $questions;
	}
	
	//========================================================
	// Returns: 2 dimensional array of candidate details
	// return[x][0] contains the ID
	// return[x][1] contains the name
	// return[x][2] contains the description
	// return[x][3] contains the url
	//
	// Called:
	// Process.php - 1
	//========================================================
	static function getAllCandidateDetailsForCurrentElection() {
		$query = "SELECT C.ID, C.candidate_name, C.userid, C.candidate_real_name, C.candidate_description, C.candidate_url, C.corp, C.alliance FROM " . QueryBuilder::candidates_table . " AS C WHERE C.election_id = " . Config::active_election . ";";
		//$query = "SELECT C.ID, C.candidate_name, C.userid, C.candidate_real_name, C.candidate_description, C.candidate_url, C.corp, C.alliance FROM " . QueryBuilder::candidates_table . " AS C RIGHT JOIN " . QueryBuilder::answers_table . " AS A ON C.ID = A.candidate_id GROUP BY C.ID WHERE C.election_id = " . Config::active_election . ";";
		
		// execute it
		$result = queryDB($query);

		$i = 0;
		while( $row = mysql_fetch_array($result) )
		{
			$questions[$i][0] = $row[0]; // id
			$questions[$i][1] = $row[1]; // eve name
			$questions[$i][2] = $row[2]; // user id
			$questions[$i][3] = $row[3]; // real name
			$questions[$i][4] = $row[4]; // description
			$questions[$i][5] = $row[5]; // url
			$questions[$i][6] = $row[6]; // corp
			$questions[$i][7] = $row[7]; // alliance
			$i++;
		}

		return $questions;
	}
	
	//========================================================
	// return the election id for a candidate
	// returns -1 if candidate was not found
	//========================================================
	static function loginCandidate($candidatename, $password) {
		$candidatename = sanitize($candidatename);
		$password = sanitize($password);
		$query = "SELECT C.election_id, C.ID FROM " . QueryBuilder::candidates_table . " AS C WHERE C.candidate_name = '" . addslashes($candidatename) . "' AND C.candidate_password = '$password' AND C.election_id = " . Config::active_election .";";
		
		//echo $query;
		// execute it
		$result = queryDB($query);
		
		$return[0] = -1;
		
		// get the value
		while( $row = mysql_fetch_array($result) ) {
			$return[0] = $row[0];
			$return[1] = $row[1];
		}
		
		return $return;
	}
	
	//========================================================
	// write candidate answers to DB
	// 
	// Called:
	// candidate_edit.php - 1
	//========================================================
	static function writeAnswers($answerdata, $total_questions, $candidateid) {
		$candidateid = sanitize($candidateid);
		
		// delete old answers if they exist
		$query = "DELETE FROM " . QueryBuilder::answers_table . " WHERE candidate_id = $candidateid;";
		queryDB($query);
		$result = "";
		for($i = 0; $i < $total_questions; $i++) {
			// make query
			$query = "INSERT INTO " . QueryBuilder::answers_table . " (candidate_id, question_id, answer, important, explanation) VALUES (";
			$query = $query . "$candidateid, " . sanitize($answerdata[$i][0]) . ", " . sanitize($answerdata[$i][1]) . ", " . sanitize($answerdata[$i][2]) . ", '" . addslashes(sanitize($answerdata[$i][3])) . "');";
			
			//$result = $result . $query . '<br />';
			// execute it
			queryDB($query);
		}
		//echo $result;
		
	}
	
	//========================================================
	// write a vote to the DB
	// 
	// Called:
	// Common_classes.php (UserInformation::setAnswers()) - n (where n = number of questions)
	//========================================================
	static function registerVote($ip_address, $electionid, $questionid, $answer, $time) {
		$ip_address = sanitize($ip_address);
		$electionid = sanitize($electionid);
		$answer = sanitize($answer);
		$questionid = sanitize($questionid);
		
		$time = sanitize($time);
		
		$query = "INSERT INTO " . QueryBuilder::votes_table . " (election_id, voter_ip, timestamp, question_id, answer) VALUES ($electionid, '$ip_address', $time, $questionid, $answer);";
		//echo $query;
		queryDB($query);
	}
}

//========================================================
// Contains all our session user information
//========================================================
class UserInformation {
	private $answers;

	//========================================================
	// Take our form input and process it
	//========================================================
	public function setAnswers($input) {
		$keys =  array_keys($input);
		$count = count($keys);
		
		$time = time();
		for($i = 0; $i < $count; $i++) {
			$questionID = $keys[$i];
			$answerCode = $input[$questionID];
			
			$answer =  translateCode($answerCode);
			
			//$this->answers[$questionID] = $answer;
			
			$this->setAnswer($questionID, $answer);
			
			// vote logging
			if(Config::log_votes == 1) {
				QueryBuilder::registerVote($_SERVER['REMOTE_ADDR'], Config::active_election, $questionID, $answer, $time);
			}
		}
	}
	
	public function setAnswer($questionID, $answer) {
		$this->answers[$questionID] = $answer;
	}

	//========================================================
	// Obtain the answer to our question
	//========================================================
	public function getAnswer($id) {
		if(isSet($this->answers[$id]))
			return $this->answers[$id];
		else
			return 0;
	}
	
	//========================================================
	// compare our questions to those of a candidate
	//========================================================
	public function compareWithCandidate($candidate) {
		$result_tally = 0;
		
		if(isSet($this->answers)) {
			$question_ids = array_keys($this->answers);
			$result_tally = 0;
			
			$count = count($question_ids);
			for($i = 0; $i < $count; $i++) {
				$id = $question_ids[$i];
				$myanswer = $this->answers[$id];
				$theiranswer = $candidate->getAnswer($id);
				$isimportant = $candidate->isImportant($id);
				$score = $this->getCandidateScore($myanswer, $theiranswer, $isimportant);
				
				/*echo '<br /><br />question: ' . $id;
				echo '<br />candidate:' . $candidate->getName();
				echo '<br />my answer: ' . $myanswer;
				echo '<br />their answer: ' . $theiranswer;
				echo '<br />this is important: ' . $isimportant;
				echo '<br /><b>resulting score: ' . $score . '</b>';*/
				
				$result_tally += $score;
				$candidate->setScore($id, $score);
			}
		}
		return $result_tally;
	}
	
	public function getAnswers() {
		return $this->answers;
	}

	//========================================================
	// translate the difference in scores
	// -2 is strongly different, +2 is exactly the same
	//========================================================
	private function getCandidateScore($myscore, $theirscore, $isimportant) {
		// General idea:
		// Agree with the candidate: increase fidelity with the candidate (by 1 or 2)
		// Disagree with the candidate: decrease fidelity with the candidate (by 1 or 2)
		// Both no opinion: increase fidelity by 1
		
		$result = 0;
		
		// early out: I have no opinion on this so it does not affect my fidelity 
		// only exception: if the candidate also does not care
		if($myscore == 0) {
			$result = 0;
				
			return $result;
		}
				
		// their score and my score are in general agreement (both agree or both disagree)
		if( ($myscore < 0 && $theirscore < 0) || ($myscore > 0 && $theirscore > 0) ) {
			// we feel exactly the same way
			if($myscore == $theirscore)
				$result = 2;
			else // we feel generally the same way
				$result = 1;
		} else {
			// minimum difference: -1
			// maximum difference: -4
			$difference = min($myscore, $theirscore) - max($myscore, $theirscore);
			
			if($difference == -1 || $difference == -2)
				$result = -1;
			else
				$result = -2;
		}
		
		// if this is an important question for the candidate
		// double the fidelity modifier
		if($isimportant == 1)
			$result = $result * 2;
			
		return $result;
	}
}

//========================================================
// Contains all our session election information
//========================================================
class CandidateInformation {
	private $id;
	private $name;
	private $description;
	private $url;
	private $answers; // [0] = answer, [1] = important, [2] = score, [3] = explanation
	private $realname;
	private $userid;
	private $corp;
	private $alliance;
	
	public function setID($input) {
		$this->id = $input;
	}
	
	public function setName($input) {
		$this->name = $input;
	}
	
	public function setDescription($input) {
		$this->description = $input;
	} 
	
	public function getDescription() {
		return $this->description;
	}
	
	public function setURL($input) {
		$this->url = $input;
	}
	
	public function getURL() {
		return $this->url;
	}
	
	public function getAnswer($id) {
		if(IsSet($this->answers[$id][0]))
			return $this->answers[$id][0];
			
		return 0;
	}
	
	public function setAnswers($input) {
		$this->answers = $input;
	}
	
	public function getAnswerIDs() {
		return array_keys($this->answers);
	}
	
	public function getName() {
		return $this->name;
	}
	
	public function setScore($id, $score) {
		$this->answers[$id][2] = $score; 
	}
	
	public function getScore($id) {
		if(IsSet($this->answers[$id][2]))
			return $this->answers[$id][2];
			
		return 0;
	}
	
	public function isImportant($id) {
		if(IsSet($this->answers[$id][1]))
			return $this->answers[$id][1];
		
		return 0;
	}
	
	public function getExplanation($id) {
		if(IsSet($this->answers[$id][3]))
			return $this->answers[$id][3];
		
		return "";
	}
	
	public function setRealName($name) {
		$this->realname = $name;
		
	}
	
	public function getRealName() {
		return $this->realname;	
	}
	
	public function setUserID($id) {
		$this->userid = $id;
	}
	
	public function getUserID() {
		if(!isset($this->userid) || $this->userid < 1)
			return 1;
			
		return $this->userid;	
	}
	
	public function setCorp($name) {
		$this->corp = $name;
	}
	
	public function getCorp() {
		return $this->corp;	
	}
	
	public function setAlliance($id) {
		$this->alliance = $id;
	}
	
	public function getAlliance() {
		return $this->alliance;	
	}
}
?>